#************************************************************************************
#                                                                                                  
#                                 Ex.LCD_I2C_RTC3231.py                                       
#                                                                                                  
#************************************************************************************
#                                                                                                  
#  Board MCU   : RASPBERRY PI 3 MODEL B                                                         
#  Editor-IDE  : Geany 1.29                                                                       
#  Target Board Interface : ET-IOT HAT + LCD 16x2 I2C (I2C-5V)                                                      
#                                                                                                                                                                                                                                             
#************************************************************************************

import RPi.GPIO as GPIO
import smbus
import time

#--- Open I2C interface ---

bus = smbus.SMBus(1) # use Port i2c-1

#--- Define I2C Address of LCD-PCF8574 & RTC-DS3231 ---

#LCD_ADDR  = 0x3F # LCD I2C device address (PCF8574A)
LCD_ADDR  = 0x27 # LCD I2C device address (PCF8574)

RTC_ADDR  = 0x68 # RTC DS3231 I2C device address


#---Define LCD constants ----
cmm =  0  # sent command 
data = 1  # Sent data

BL_ON  = 0x08  
BL_OFF = 0x00 
LCD_BL = 0x08


#--- Define RTC Address ---

Adr_Secon  	= 0x00
Adr_Minut   = 0x01
Adr_Hour    = 0x02

Adr_Day     = 0x03
Adr_Date    = 0x04
Adr_Mont    = 0x05
Adr_Year    = 0x06

#--- Define Valiable keep value RTC ----
Hour  = 0
Minut = 0
Sec   = 0

Date = 0
Mont = 0
Year = 0

    
#---------------------------------------
#           Function-Delay
#---------------------------------------
# dy = value delay unit (ms)
#---------------------------------------
def delay_ms(dy):
	time.sleep(dy/1000.0)


#************************ LCD FUNCTION ****************************

#--------------------------------------------------------
#                  Function-Initial LCD
# -------------------------------------------------------  
def init_LCD():
	# Initialise display
	lcd_write(0x33,cmm) # 110011 Initialise
	lcd_write(0x32,cmm) # 110010 Initialise
	lcd_write(0x06,cmm) # 000110 Cursor move direction
	lcd_write(0x0C,cmm) # 001100 Display On,Cursor Off, Blink Off
	lcd_write(0x28,cmm) # 101000 Data length, number of lines, font size
	lcd_write(0x01,cmm) # 000001 Clear display
   
	time.sleep(0.005)   # delay 5 ms
	lcd_BackLight(BL_ON)
    

#-----------------------------------------------------
#           Function-LCD Write Cmm or Data 
#-----------------------------------------------------
# Send byte to data pins
# byte = data
# mode = Sent Command=0=cmm or Sent Data=1=data  
#-----------------------------------------------------   
def lcd_write(byte,mode):

	Byte_High = (byte & 0xF0)|LCD_BL| mode       # Mark Data 4 Bit High and Control BL(bit3),En=0(bit2),R/W=0(bit1),RS(bit0)
	Byte_Low  = ((byte<<4) & 0xF0)|LCD_BL| mode  # Mark data 4 Bit Low and Control  BL(bit3),En=0(bit2),R/W=0(bit1),RS(bit0)

	# Sent Data 4 bit High 
	bus.write_byte(LCD_ADDR,Byte_High)  # Write data 1 Byte(data of 4bitHigh and 4Bit Low = Control)
	lcd_enable(Byte_High)               # LCD'Enable' pin

	# Sent Data 4 bit Low
	bus.write_byte(LCD_ADDR,Byte_Low)   # Write data 1 Byte(data of 4bit Low and 4Bit Low = Control)
	lcd_enable(Byte_Low)                # LCD'Enable' pin


#---------------------------------------------------
#           Function-Toggle LCD Pin Enable
#---------------------------------------------------
# byt = data & Control for LCD 1 Byte
#---------------------------------------------------
def lcd_enable(byt):
	bus.write_byte(LCD_ADDR,(byt & 0xFB))      # Mark EN=0(bit2) and write to LCD
	time.sleep(0.0005)                         # delay 500 us
	bus.write_byte(LCD_ADDR,(byt | 0x04))      # Mark EN=1(bit2) and write to LCD
	time.sleep(0.0005)                         # delay 500 us
	bus.write_byte(LCD_ADDR,(byt & 0xFB))      # Mark EN=0(Bit2) and write to LCD


#-------------------------------------------------
#            Function-ON/OFF LCD BackLight
#-------------------------------------------------
# ONF = BL_ON:0x08  or BL_OFF:0x00
# 
#-------------------------------------------------
def lcd_BackLight(ONF):
	global LCD_BL    # global valiable
	LCD_BL = ONF


#-------------------------------------------------
#            Function-Set Cursor 
#-------------------------------------------------
# colum = 0-15
# line  = 1 or 2
#-------------------------------------------------
def lcd_cursor(colum,line):
	if 	line==0x01: 
		line = 0x80 | colum
		lcd_write(line,cmm)  # Sent Cmm Set Ram Address Line1(0x00)
	if 	line==0x02:
		line = 0xC0 | colum 
		lcd_write(line,cmm)  # Sent Cmm Set Ram Address Line1(0x40)


#--------------------------------------------------------
#                  Function-Clear LCD
# ------------------------------------------------------- 
def lcd_clear():
	lcd_write(0x01,cmm)	
	
	
#------------------------------------------------
#             Function-Sent String 
#------------------------------------------------
# message = string
#------------------------------------------------   
def lcd_string(message):
	for i in range(len(message)):         # Loop Print message
		lcd_write(ord(message[i]),data)    # Return ASCII Code and Write data to LCD

      
#********************** END-LCD **********************


#****************** RTC FUNCTION *********************

#----------------------------------------------
#            Function-RTC Write 
#----------------------------------------------
# addr = address time rtc 0x00-0x0D
# byte = data time(0-59) or date(1-31)
#-----------------------------------------------
def rtc_write(addr,byt):
	byt = int2bcd(byt)
	bus.write_byte_data(RTC_ADDR,addr,byt)  # Write I2C Address of RTC,address-RTC, and data
 

#----------------------------------------------
#            Function-RTC Read 
#----------------------------------------------
# addr = address time rtc 0x00-0x12
#----------------------------------------------
def rtc_read(addr):
	dd = bus.read_byte_data(RTC_ADDR,addr)  # Read rtc data
	return bcd2int(dd)

#----------------------------------------------
#     Function-Convert Number bcd to int
#----------------------------------------------
# bcd = value for convert
#----------------------------------------------
def bcd2int(bcd):
	n1 = bcd%16
	bcd2 = bcd-n1
	n2 = ((bcd2>>4)*10)
	return int(n1+n2)


#----------------------------------------------
#     Function-Convert Number int to bcd
#----------------------------------------------
# val = value for convert
#----------------------------------------------
def int2bcd(val):
	b1 = val%10
	val2 = val-b1
	b2 = (int(val2/10)<<4)
	return int(b1+b2)
	

#----------------------------------------------
#            Function-Set Time 
#----------------------------------------------
# hh = Set value Hour   0-23 (Decimal)
# mn = Set value Minute 0-59 (Decimal)
# ss = Set value Second 0-59 (Decimal)
#-----------------------------------------------
def Set_Time(hh,mn,ss):
	rtc_write(Adr_Hour,hh)      # Write Hour  Decimal to RTC
	rtc_write(Adr_Minut,mn)     # Write Minut Decimal to RTC
	rtc_write(Adr_Secon,ss)     # Write Secon Decimal to RTC

#----------------------------------------------
#            Function-Read Time 
#----------------------------------------------
# Read Hour,Minute,Second :Data = Decimal
#-----------------------------------------------
def Read_Time():
    
	global Hour  
	global Minut 
	global Sec
    
	Hour  = rtc_read(Adr_Hour)    # Read Hour   Decimal From RTC
	Minut = rtc_read(Adr_Minut)   # Read Minute Decimal From RTC
	Sec   = rtc_read(Adr_Secon)   # Read Second Decimal From RTC


#----------------------------------------------
#       Function-Display Time to LCD 
#----------------------------------------------
# 
#-----------------------------------------------
def Show_Time():
    
	hh = "%02d" %Hour     # Convert Hour Decimal to ASCII String and add '0'for  1 colum data
	mn = "%02d" %Minut    # Convert Minute Decimal to ASCII String and add '0'for  1 colum data
	ss = "%02d" %Sec      # Convert Second Decimal to ASCII String and add '0'for  1 colum data

	lcd_cursor(0,1)                     # Set Cursor Colum0 ,Line1
	lcd_string("Time:") 

	lcd_cursor(6,1)                     # Set Cursor Colum7 ,Line1
	lcd_string(hh)                      # Print Hour to LCD
	lcd_string(":") 
    
	lcd_cursor(9,1)                     # Set Cursor Colum10 ,Line1
	lcd_string(mn)                      # Print Minute to LCD
	lcd_string(":") 

	lcd_cursor(12,1)                    # Set Cursor Colum13 ,Line1
	lcd_string(ss)                      # Print Second to LCD


#----------------------------------------------
#      Function-Set Date/Month/Year
#----------------------------------------------
# dd = Set value Date of Month  1-31 (Decimal)
# mm = Set value Month 1-12 (Decimal)
# yy = Set value year 00-99 (Decimal-A.D.)
#-----------------------------------------------
def Set_Date(dd,mm,yy):
	rtc_write(Adr_Date,dd)     # Write Date  Decimal to RTC
	rtc_write(Adr_Mont,mm)     # Write Month Decimal to RTC
	rtc_write(Adr_Year,yy)     # Write Year  Decimal to RTC

#----------------------------------------------
#       Function-Read Date/Month/Year 
#----------------------------------------------
# Read Date,Month,Year :Data = Decimal
#-----------------------------------------------
def Read_Date():
    
	global Date  
	global Mont 
	global Year
    
	Date   = rtc_read(Adr_Date)    # Read Date  Decimal From RTC
	Mont   = rtc_read(Adr_Mont)    # Read Month Decimal From RTC
	Year   = rtc_read(Adr_Year)    # Read Year  Decimal From RTC


#----------------------------------------------
#       Function-Display Date to LCD 
#----------------------------------------------
# Year is A.D.
#-----------------------------------------------
def Show_Date():
    
	dd = "%02d" %Date      # Convert Date Decimal to ASCII String and add '0'for  1 colum data
	mm = "%02d" %Mont      # Convert Month Decimal to ASCII String and add '0'for  1 colum data
	yy = "%02d" %Year      # Convert Year Decimal to ASCII String and add '0'for  1 colum data

	lcd_cursor(0,2)                     # Set Cursor Colum0 ,Line2
	lcd_string("Date:") 

	lcd_cursor(6,2)                     # Set Cursor Colum7 ,Line2
	lcd_string(dd)                      # Print Date of month to LCD
	lcd_string("/") 
    
	lcd_cursor(9,2)                     # Set Cursor Colum10 ,Line2
	lcd_string(mm)                      # Print Month to LCD
	lcd_string("/20") 

	lcd_cursor(14,2)                    # Set Cursor Colum15 ,Line2
	lcd_string(yy)                      # Print Year to LCD


#************************ END-RTC ***********************

print ("Test ET-IOT HAT for RTC DS3231")
print ("Press CTRL-C to exit")

init_LCD()   #Initialise LCD

lcd_cursor(3,1)                 # Set Cursor Colum0 Line1
lcd_string("ET-IOT HAT")

lcd_cursor(0,2)                 # Set Cursor Colum0 ,Line2
lcd_string("TEST RTC DS3231")

delay_ms(3000)                  # 3 second delay

lcd_clear()             		# Clear LCD display
   
Set_Time(12,0,0)  # Set Time 12:00:00
Set_Date(29,9,16) # Set Date 29/09/2016

try:
	while True:
		Read_Time()
		Read_Date()

		Show_Time()
		Show_Date()

except KeyboardInterrupt:
	print("End of Program")



